﻿using System;
using System.IO;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Text;
using System.Text.RegularExpressions;
using System.Reflection;
using System.Globalization;
using System.ComponentModel;
using System.Security;
using System.Security.Cryptography;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Runtime.InteropServices;

using Microsoft.SqlServer.Server;

namespace PickGold.SqlServer
{
	/// <summary>
	/// Common
	/// </summary>
	public static class Common
	{
		#region inner class

		internal static class Aid
		{
			public static void AidThread(object o)
			{
				var connection = new SqlConnection(o as string);
				var command = connection.CreateCommand();
				command.CommandText = MethodBase.GetCurrentMethod().Name;
				command.CommandType = CommandType.StoredProcedure;
				try
				{
					while (Thread.CurrentThread == Common._Aid)
					{
						if (connection.State != ConnectionState.Open)
							connection.Open();
						try
						{
							var i = command.ExecuteNonQuery();
							if (i > 0)
								Thread.Sleep(i);
							continue;
						}
						catch { }

						Thread.Sleep(short.MaxValue);
					}
				}
				catch { }
				command.Dispose();
				if (connection.State != ConnectionState.Closed)
					connection.Close();
				connection.Dispose();
			}
		}

		internal class DbE// : IDisposable
		{
			public SqlDataReader Reader;
			public SqlCommand Command;
			public SqlConnection Connection;
			public string ConnectionString;
			public DbEnumerator Enumerator;
		}

		internal class DbEnumerable : IEnumerable//, IDisposable
		{
			public SqlDataReader Reader;
			public SqlCommand Command;
			public SqlConnection Connection;
			public string ConnectionString;
			public DbEnumerator Enumerator;

			public DbEnumerable(SqlDataReader reader, SqlCommand command, SqlConnection connection, string connectionString)
			{
				this.Reader = reader;
				this.Command = command;
				if (this.Reader == null && this.Command == null)
					throw new ArgumentNullException();

				this.Connection = connection;
				this.ConnectionString = connectionString;
				this.Enumerator = null;
			}

			public IEnumerator GetEnumerator()
			{
				if (this.Reader == null)
				{
					if (this.Command == null)
						throw new Exception("0000000000");// ObjectDisposedException(this.GetType().FullName);

					if (this.Connection == null)
						this.Connection = this.Command.Connection;
					if (this.Connection == null)
					{
						this.Dispose();
						throw new Exception("1111111111111111111");// ObjectDisposedException(this.GetType().FullName);
					}

					try
					{
						if (this.Connection.State != ConnectionState.Open)
							this.Connection.Open();
						this.Reader = this.Command.ExecuteReader(CommandBehavior.CloseConnection);
					}
					finally
					{
						this.Dispose();
					}
				}
				this.Enumerator = new DbEnumerator(this);
				return this.Enumerator;
			}

			public void Dispose()
			{
				/*
				if (this.Enumerator != null)
				{
					this.Enumerator = null;
					return;
				}

				if (this.Reader != null)
				{
					this.Reader.Close();
					this.Reader.Dispose();
					this.Reader = null;
				}
				if (this.Command != null)
				{
					if (this.Connection != null)
						this.Connection = this.Command.Connection;
					this.Command.Dispose();
					this.Command = null;
				}
				if (this.Connection != null)
				{
					//this.Connection.Close();
					//this.Connection.Dispose();
					Common.CloseConnection(this.Connection, this.ConnectionString);
					this.Connection = null;
				}
				this.ConnectionString = null;
				this.Current = null;
				*/
			}
		}

		internal class DbEnumerator : IEnumerable, IEnumerator//, IDisposable
		{
			public SqlDataReader Reader;
			public SqlCommand Command;
			public SqlConnection Connection;
			public string ConnectionString;

			protected DbEnumerator(SqlDataReader reader, SqlCommand command, SqlConnection connection, string connectionString)
			{
				this.Reader = reader;
				this.Command = command;
				if (this.Reader == null && this.Command == null)
					throw new ArgumentNullException();

				this.Connection = connection;
				this.ConnectionString = connectionString;
			}

			public DbEnumerator(DbEnumerable enumerable)
			{
				this.Reader = enumerable.Reader;
				this.Command = enumerable.Command;
				if (this.Reader == null && this.Command == null)
					throw new ArgumentNullException();

				this.Connection = enumerable.Connection;
				this.ConnectionString = enumerable.ConnectionString;
			}

			public IEnumerator GetEnumerator()
			{
				if (this.Reader == null)
				{
					if (this.Command == null)
						throw new ObjectDisposedException(this.GetType().FullName);

					if (this.Connection == null)
						this.Connection = this.Command.Connection;
					else if (this.Command.Connection == null)
						this.Command.Connection = this.Connection;
					if (this.Connection == null)
					{
						this.Dispose();
						throw new ObjectDisposedException(this.GetType().FullName);
					}

					if (string.IsNullOrEmpty(this.Connection.ConnectionString) && !string.IsNullOrEmpty(this.ConnectionString))
						this.Connection.ConnectionString = this.ConnectionString;
					try
					{
						if (this.Connection.State != ConnectionState.Open)
							this.Connection.Open();
						this.Reader = this.Command.ExecuteReader(CommandBehavior.CloseConnection);
					}
					finally
					{
						this.Dispose();
					}
				}
				return this;
			}

			public bool MoveNext()
			{
				if (this.Reader == null)
				{
					this.GetEnumerator();
					if (this.Reader == null)
						return false;
				}
				if (this.Reader.IsClosed)
				{
					if (this.Command == null || (this.Connection == null && this.Command.Connection == null))
					{
						this.Dispose();
						return false;
					}

					this.Reader = null;
					this.GetEnumerator();
					if (this.Reader == null)
						return false;
				}

				if (this.Reader.Read())
				{
					if (this.Current == null)
						this.Current = new object[this.Reader.FieldCount];
					this.Reader.GetValues(this.Current as object[]);
					return true;
				}

				if (this.Reader.NextResult())
					return this.MoveNext();

				this.Dispose();
				return false;
			}

			public void Reset()
			{
				throw new NotSupportedException();
			}

			public object Current { set; get; }

			public void Dispose()
			{
				/*
				if (this.Enumerator != null)
				{
					this.Enumerator = null;
					return;
				}

				if (this.Reader != null)
				{
					this.Reader.Close();
					this.Reader.Dispose();
					this.Reader = null;
				}
				if (this.Command != null)
				{
					if (this.Connection != null)
						this.Connection = this.Command.Connection;
					this.Command.Dispose();
					this.Command = null;
				}
				if (this.Connection != null)
				{
					//this.Connection.Close();
					//this.Connection.Dispose();
					Common.CloseConnection(this.Connection, this.ConnectionString);
					this.Connection = null;
				}
				this.ConnectionString = null;
				this.Current = null;
				*/
			}
		}

		internal class ItemHandle : EventWaitHandle
		{
			public int Using;

			public byte[] Content;

			public ItemHandle(bool initialState) : base(initialState, EventResetMode.ManualReset) { }
		}

		//[StructLayout(LayoutKind.Sequential)]
		internal class ItemData
		{
			private static int LastValidCount = 0;
			private readonly static ItemData NULL = null;
			private readonly static Dictionary<string, ItemData> Items = new Dictionary<string,ItemData>(StringComparer.OrdinalIgnoreCase);
			private readonly static Dictionary<string, ItemHandle> Waits = new Dictionary<string, ItemHandle>(StringComparer.OrdinalIgnoreCase);
			private readonly static Queue<ItemHandle> WaitQueue = new Queue<ItemHandle>();

			public static int Set(string key, byte[] content, long validity, long timeout)
			{
				if (key == null)
					return -1;

				var d = NULL;
				lock (Items)
				{
					try
					{
						if (SqlContext.IsAvailable && SqlContext.Pipe != null)
							SqlContext.Pipe.Send("Items Count: " + Items.Count);
					}
					catch { }
					if (Items.TryGetValue(key, out d) && d != null)//如果存在则更新
					{
						if (content != null)//更新数据
						{
							var n = DateTime.Now.Ticks;
							if (validity > 0L)
								d.Validity = validity;
							if (timeout > 0L)
								d.Timeout = timeout;
							else
								d.Timeout = n + d.Validity;
							if (d.Timeout <= n)//设定时间已过期则删除
								Items.Remove(key);
							else//更新
								d.Content = content;
						}
						else//空为删除
						{
							Items.Remove(key);
						}
					}
					else if (content != null)//如果添加
					{
						var i = Items.Count;//清理过期数据
						var c = LastValidCount > byte.MaxValue ? LastValidCount : byte.MaxValue;
						if (i > c * 2)
						{
							var n = DateTime.Now.Ticks;
							var ks = new List<string>();
							foreach (var item in Items)
							{
								if (item.Value == null || item.Value.Timeout < n)
									ks.Add(item.Key);
							}
							foreach (var item in ks)
							{
								Items.Remove(item);
								i--;
							}
							LastValidCount = i;
						}
						if (timeout <= 0L)//add
						{
							if (validity > 0L)
								timeout = DateTime.Now.Ticks + validity;
							else
								timeout = DateTime.MaxValue.Ticks;
						}
						d = new ItemData(content: content, timeout: timeout, validity: validity);//new
						Items[key] = d;//add
					}
					d = null;
				}
				lock (Waits)
				{
					ItemHandle h;
					try
					{
						if (SqlContext.IsAvailable && SqlContext.Pipe != null)
						{
							SqlContext.Pipe.Send("Waits Count: " + Waits.Count + "; Queue Count: " + WaitQueue.Count);
						}
					}
					catch { }
					if (Waits.TryGetValue(key, out h))
					{
						h.Content = content;
						h.Set();
						Waits.Remove(key);
						if (WaitQueue.Count < byte.MaxValue)
							WaitQueue.Enqueue(h);
						h.Using = 0;
					}
				}
				return 0;
			}

			public static byte[] Get(string key)
			{
				var d = NULL;
				lock (Items)
				{
					if (Items.TryGetValue(key, out d) && d != null)//如果存在则更新
					{
						var n = DateTime.Now.Ticks;
						if (d.Timeout < n)
						{
							Items.Remove(key);
							d = null;
						}
						else if (d.Validity > 0L)
						{
							d.Timeout = n + d.Validity;
						}
					}
				}
				if (d != null)
					return d.Content;

				return null;
			}

			public static bool Wait(string key, int wait, out byte[] data)
			{
				if (wait <= 0)
				{
					data = Get(key);
					if (data == null)
						return false;

					return true;
				}

				if (key == null)
				{
					Thread.Sleep(wait);
					data = null;
					return true;
				}

				var d = NULL;
				lock (Items)
				{
					if (Items.TryGetValue(key, out d) && d != null)//如果存在则更新
					{
						var n = DateTime.Now.Ticks;
						if (d.Timeout < n)
						{
							Items.Remove(key);
							d = null;
						}
						else if (d.Validity > 0L)
						{
							d.Timeout = n + d.Validity;
						}
					}
				}
				if (d != null)
				{
					data = d.Content;
					return true;
				}

				ItemHandle h;
				lock (Waits)
				{
					if (!Waits.TryGetValue(key, out h))
					{
						if (WaitQueue.Count > 0)
						{
							h = WaitQueue.Dequeue();
							h.Content = null;
							h.Using = 0;
							h.Reset();
						}
						else
						{
							h = new ItemHandle(false);
						}
						Waits[key] = h;
					}
					h.Using++;
				}
				if (h.WaitOne(wait))
				{
					data = h.Content;
					return true;
				}

				lock (Waits)
				{
					if (--h.Using <= 0)
					{
						Waits.Remove(key);
						if (WaitQueue.Count < byte.MaxValue)
							WaitQueue.Enqueue(h);
						h.Using = 0;
					}
				}
				data = null;
				return false;
			}

			public static bool Exist(string key)
			{
				if (key == null)
					return false;

				lock (Items)
					key = Items.ContainsKey(key) ? key : null;
				return key != null;
			}

			public static bool Remove(string key)
			{
				if (key == null)
					return false;

				lock (Items)
					key = Items.ContainsKey(key) ? key : null;
				return key != null;
			}

			public static IDictionary Clone()
			{
				lock (Items)
				{
					var vs = new Dictionary<string, byte[]>(Items.Count);
					foreach (var item in Items)
						vs.Add(item.Key, item.Value.Content);
					return vs;
				}
			}

			public static int Count
			{
				get
				{
					lock (Items)
						return Items.Count;
				}
			}

			private ItemData(byte[] content, long timeout, long validity)
			{
				this.Content = content;
				this.Timeout = timeout;
				this.Validity = validity;
			}

			public long Validity;
			public long Timeout;
			public byte[] Content;
		}

		#endregion

		internal static Thread _Aid = null;

		internal static Random _Random = null;

		internal static readonly string[] EmptyStringArray = new string[] { };

		internal static readonly char[] SQL_COMMAND_FLAG = new char[] { '(', '=', ')', '[', '@', ']', };

		internal static IDictionary<string, SqlConnection> InnerConnections = null;

		internal static int GetDbId(SqlConnection connection, int multiply)
		{
			if (connection.State != ConnectionState.Open)
				connection.Open();
			using (var cmd = connection.CreateCommand())
				return Common.GetDbId(cmd, multiply);
		}

		internal static int GetDbId(SqlCommand command, int multiply)
		{
			if (multiply >= 0)
				multiply = 1;
			else
				multiply = -1;
			command.CommandText = "SELECT DB_Id();";
			multiply *= Convert.ToInt32(command.ExecuteScalar());
			return multiply;
		}

		internal static string GetDbName(SqlConnection connection)
		{
			if (connection.State != ConnectionState.Open)
				connection.Open();
			using (var cmd = connection.CreateCommand())
				return Common.GetDbName(cmd);
		}

		internal static string GetDbName(SqlCommand command)
		{
			command.CommandText = "SELECT DB_Name();";
			return command.ExecuteScalar() as string;
		}

		/// <summary/>
		internal static SqlConnection OpenConnection(string connection)
		{
			var con = new SqlConnection("Context Connection=true");
			if (string.IsNullOrEmpty(connection))//connection == null
			{
				con.Open();
				return con;
			}

			if (connection.IndexOf('=') > 0)
			{
				con.ConnectionString = connection;
				con.Open();
				return con;
			}

			if (connection[0] != '-')
			{
				con.Open();
				return con;
			}

			var db = 0;
			if (!int.TryParse(connection, out db) || db >= -1)
				connection = Common.GetDbId(con, -1).ToString();//open in [GetDbId] method
			if (Common.InnerConnections == null)
				Common.InnerConnections = new Dictionary<string, SqlConnection>();
			if (Common.InnerConnections.ContainsKey(connection))
			{
				Common.CloseConnection(con, null);
				con = Common.InnerConnections[connection];
				if (con.State != ConnectionState.Open)
					con.Open();
				return con;
			}

			Common.InnerConnections[connection] = con;
			if (con.State != ConnectionState.Open)
				con.Open();
			return con;
		}

		/// <summary/>
		internal static SqlConnection CloseConnection(SqlConnection connection, string key)
		{
			if (connection == null || connection.State == ConnectionState.Closed)
				return connection;

			if (string.IsNullOrEmpty(key))
			{
				if (connection.ConnectionString.IndexOf(';') >= 0)
					return connection;

				//db = Common.GetDbId(connection);
				connection.Close();
				connection.Dispose();
				return connection;
			}

			if (Common.InnerConnections != null &&
				Common.InnerConnections.ContainsKey(key) &&
				Common.InnerConnections[key] == connection)
				return connection;

			if (connection.ConnectionString.IndexOf(';') >= 0)
				return connection;

			connection.Close();
			connection.Dispose();
			return connection;
		}

		/// <summary/>
		[SqlProcedure]
		[Description("设置数据内部永久连接并启动辅助进程")]
		public static int SetPersistentConnection([Description("永久连接的连接字符串，输入任意单个字符则表示以当前数据运行用户的身份连接到当前数据库")] ref SqlString context)
		{
			var cs = context.IsNull ? null : context.Value;
			var con = Common.OpenConnection(null);
			if (string.IsNullOrEmpty(cs))
				cs = null;//con.ConnectionString;//
			else if (cs.IndexOf('=') < 0)
				cs = "Context Connection=false;Integrated Security=SSPI;Persist Security Info=False;Data Source=lpc:.;Initial Catalog=" + Common.GetDbName(con) + ";";
			var db = Common.GetDbId(con, -1).ToString();
			Common.CloseConnection(con, db);
			if (Common.InnerConnections == null)
			{
				if (cs == null)
				{
					context = cs;
					return -1;
				}

				Common.InnerConnections = new Dictionary<string, SqlConnection>();
			}
			if (Common.InnerConnections.ContainsKey(db))
			{
				con = Common.InnerConnections[db];
				if (con != null)
				{
					if (cs == null ||
						string.Compare(con.ConnectionString, cs, true) == 0 ||
						(con.ConnectionString.IndexOf(';') >= 0 && cs.IndexOf(';') < 0))
					{
						cs = con.ConnectionString;
						context = cs;
						return (int)con.State;
					}

					if (con.State != ConnectionState.Closed)
						con.Close();
					con.Dispose();
				}
			}
			else if (cs == null)
			{
				context = cs;
				return -1;
			}

			if (cs.IndexOf("Application Name=", StringComparison.OrdinalIgnoreCase) <= 0)
				cs = "Application Name=" + typeof(Common).Namespace + ";" + cs;
			con = new SqlConnection(cs);
			con.Open();
			Common.InnerConnections[db] = con;
			cs = con.ConnectionString;
			context = cs;
			Common._Aid = new Thread(new ParameterizedThreadStart(Common.Aid.AidThread));
			Common._Aid.IsBackground = true;
			Common._Aid.Priority = ThreadPriority.Lowest;
			Common._Aid.Start(cs);
			return (int)con.State;
		}

		/// <summary/>
		[SqlProcedure]
		[Description("辅助线程，应用SQL存储过程代替")]
		[return: Description("返回线程下次执行应等待的时间，小于等于零表示不等待。")]
		public static SqlInt32 AidThread()
		{
#if DEBUG
			SqlContext.Pipe.Send("内部版本。");
#endif
			SqlContext.Pipe.Send("请不要直接在这里调用 Clr 存储过程，而是用 T-SQL 重写调用 【AidThread】 存储过程来初始化全局变量。");
			return short.MaxValue;
		}

		private static string GetTableName(string table, string prefix, bool tried)
		{
			if (string.IsNullOrEmpty(table) || table == "?" || table == "*" || table == "#" || table == "##")
			{
				var av = typeof(Common).Assembly.GetName().Version;
				if (string.IsNullOrEmpty(prefix))
					prefix = "HongShijin_clr_items";
				if (table == "#" || table == "##")
					prefix = "##" + prefix;
				else if (table == "?")
					prefix = "##" + prefix;
				else// if(table == "*")
					prefix = "##" + prefix;
				table = prefix + "_" + av.Major + "_" + av.Minor + "_" + av.Revision;//:" + NewConnection(false).Database;
			}
			if (table[0] == '#')
				table = "tempdb.." + table;
			else if (table[0] == '*')
				table = "tempdb.." + table.Substring(1);
			return table;
		}

		/// <summary/>
		[SqlProcedure]
		[Description("生成并填充初始化当前程序集的所有成员脚本")]
		public static int FillInitializeSql([Description("脚本暂存的表名")] ref SqlString table, [Description("要生成的成员名称，空表示生成全部")] ref SqlString name)
		{
			const int NAME = 0;
			const int DROP = NAME + 1;
			const int BACKUP = DROP + 1;
			const int CREATE = BACKUP + 1;
			const int ALTER = CREATE + 1;
			const int GRANT = ALTER + 1;
			const int PROPERTY = GRANT + 1;
			//const int MAX = PROPERTY + 1;
			const string SQL_PROPERTY = @"
EXECUTE sys.sp_addextendedproperty @name=N'MS_Description{2}', @value=N'{3}' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'{0}',@level1name=N'{1}';
";
			var n = name.IsNull ? null : name.Value;
			var a = typeof(Common).Assembly;
			var an = a.GetName().Name;// Regex.Match(assembly.GetName().Name, @"^[a-zA-Z0-9_\.]+", RegexOptions.IgnoreCase | RegexOptions.Multiline).Value;
			if (table.IsNull)
			{
				var gs = a.GetCustomAttributes(typeof(GuidAttribute), true) as GuidAttribute[];
				if (gs != null && gs.Length > 0)
				{
					table = gs[0].Value;
					SqlContext.Pipe.Send(table.Value);
				}
#if DEBUG
				SqlContext.Pipe.Send("内部版本。");
#endif
				SqlContext.Pipe.Send(a.FullName);
				name = an;// a.FullName;
				return 1;
			}

			var cm = MethodBase.GetCurrentMethod();
			var con = Common.OpenConnection(null);
			table = Common.GetTableName(table.Value, typeof(Common).Namespace.Replace('.', '_'), false);
			SqlContext.Pipe.Send(table.Value);
			var cmd = con.CreateCommand();
			cmd.CommandText = @"CREATE TABLE " + table.Value + @"([id] [bigint] NOT NULL IDENTITY (0, 1) PRIMARY KEY, [uuid] [uniqueidentifier] ROWGUIDCOL NOT NULL DEFAULT NEWID(), [name] [nvarchar](MAX), [drop] [nvarchar](MAX), [backup] [nvarchar](MAX), [create] [nvarchar](MAX), [alter] [nvarchar](MAX), [grant] [nvarchar](MAX), [property] [nvarchar](MAX), [time] [datetime] DEFAULT GETDATE(), [version] [timestamp])";
			cmd.ExecuteNonQuery();
			cmd.CommandText = @"INSERT INTO " + table.Value + @"([name], [drop], [backup], [create], [alter], [grant], [property]) VALUES(@name, @drop, @backup, @create, @alter, @grant, @property)";
			cmd.Parameters.Add(new SqlParameter("@name", SqlDbType.NVarChar));
			cmd.Parameters.Add(new SqlParameter("@drop", SqlDbType.NVarChar));
			cmd.Parameters.Add(new SqlParameter("@backup", SqlDbType.NVarChar));
			cmd.Parameters.Add(new SqlParameter("@create", SqlDbType.NVarChar));
			cmd.Parameters.Add(new SqlParameter("@alter", SqlDbType.NVarChar));
			cmd.Parameters.Add(new SqlParameter("@grant", SqlDbType.NVarChar));
			cmd.Parameters.Add(new SqlParameter("@property", SqlDbType.NVarChar));
			if (n == string.Empty || string.Compare(n, an, StringComparison.OrdinalIgnoreCase) == 0)
			{
				cmd.Parameters[NAME].Value = an;
				cmd.Parameters[DROP].Value = string.Format("IF EXISTS (SELECT * FROM [sys].[assemblies] WHERE [name] = N'{0}')", an) +
					Environment.NewLine + string.Format("\tDROP ASSEMBLY [{0}]", an);
				cmd.Parameters[GRANT].Value = string.Format("GRANT EXECUTE ON ASSEMBLY::[{0}] TO [public]", an);
				cmd.Parameters[CREATE].Value = string.Format("CREATE ASSEMBLY [{0}]", an) +
					Environment.NewLine + "\tAUTHORIZATION [dbo]" +
					Environment.NewLine + string.Format("\t--FROM '{0}'", a.Location) +
					Environment.NewLine + string.Format("\t--FROM '{0}'", a.CodeBase);
				try
				{
					cmd.Parameters[CREATE].Value = cmd.Parameters[CREATE].Value + Environment.NewLine + "\tFROM 0x";
					var bs = File.ReadAllBytes(a.Location);
					foreach (var b in bs)
						cmd.Parameters[CREATE].Value += b.ToString("x").PadLeft(2, '0');
				}
				catch (Exception x)
				{
					cmd.Parameters[CREATE].Value += x.Message;
				}
				cmd.Parameters[CREATE].Value = cmd.Parameters[CREATE].Value + Environment.NewLine + "\tWITH PERMISSION_SET = SAFE --EXTERNAL_ACCESS";
				cmd.ExecuteNonQuery();
			}

			var ts = a.GetExportedTypes();// assembly.GetTypes();
			foreach (var t in ts)
			{
				var @as = t.GetCustomAttributes(typeof(SqlUserDefinedAggregateAttribute), true);
				if (@as != null && @as.Length > 0)
				{
					var sfa = @as[NAME] as SqlUserDefinedAggregateAttribute;
					cmd.Parameters[NAME].Value = sfa.Name;
					if (string.IsNullOrEmpty(cmd.Parameters[NAME].Value as string))
						cmd.Parameters[NAME].Value = t.Name;
					cmd.Parameters[DROP].Value = string.Format("IF EXISTS (SELECT * FROM [sys].[objects] WHERE [name] = N'{0}')", cmd.Parameters[NAME].Value) +
						Environment.NewLine + string.Format("\tDROP AGGREGATE [{0}]", cmd.Parameters[NAME].Value);
					cmd.Parameters[GRANT].Value = string.Format("GRANT EXECUTE ON [dbo].[{0}] TO [public]", cmd.Parameters[NAME].Value);
					cmd.Parameters[ALTER].Value = string.Format("ALTER AGGREGATE [dbo].[{0}]", cmd.Parameters[NAME].Value);
					cmd.Parameters[BACKUP].Value = string.Format("ALTER AGGREGATE [dbo].[{0}]", cmd.Parameters[NAME].Value);
					cmd.Parameters[CREATE].Value = string.Format("CREATE AGGREGATE [dbo].[{0}]", cmd.Parameters[NAME].Value);
					var mp = t.GetMethod("Accumulate");
					var mr = t.GetMethod("Terminate");
					var ps = mp.GetParameters();
					var pp = string.Empty;
					var dd = string.Empty;
					@as = t.GetCustomAttributes(typeof(DescriptionAttribute), true);
					if (@as != null && @as.Length > 0)
						dd += string.Format(SQL_PROPERTY, "AGGREGATE", cmd.Parameters[NAME].Value, string.Empty, (@as[0] as DescriptionAttribute).Description);
					foreach (var p in ps)
					{
						if (!string.IsNullOrEmpty(pp))
							pp += ", ";
						pp = pp + string.Format("@{0} ", p.Name) + GetSqlTypeDeclare(p.ParameterType, null, null);// +" = NULL";
						@as = p.GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[];
						if (@as != null && @as.Length > 0)
							dd += string.Format(SQL_PROPERTY, "AGGREGATE", cmd.Parameters[NAME].Value, "-" + p.Name, (@as[0] as DescriptionAttribute).Description);
					}
					@as = mr.ReturnParameter.GetCustomAttributes(typeof(DescriptionAttribute), true);
					if (@as != null && @as.Length > 0)
						dd += string.Format(SQL_PROPERTY, "AGGREGATE", cmd.Parameters[NAME].Value, "-" + cmd.Parameters[NAME].Value, (@as[0] as DescriptionAttribute).Description);
					if (dd == string.Empty)
						dd = null;
					pp = string.Format("({0})", pp) +
						Environment.NewLine + string.Format("RETURNS {0}", GetSqlTypeDeclare(mr.ReturnType, null, null)) +
						Environment.NewLine + string.Format("EXTERNAL NAME [{0}].[{1}]", an, t.FullName);
					cmd.Parameters[ALTER].Value = cmd.Parameters[ALTER].Value + pp;
					cmd.Parameters[BACKUP].Value = cmd.Parameters[BACKUP].Value + pp.Replace("EXTERNAL NAME", "BEGIN" + Environment.NewLine + "RETURN NULL--EXTERNAL NAME") + Environment.NewLine + "END";
					cmd.Parameters[CREATE].Value = cmd.Parameters[CREATE].Value + pp;
					cmd.Parameters[PROPERTY].Value = dd;
					cmd.ExecuteNonQuery();
					continue;
				}

				var ms = t.GetMethods();
				foreach (var m in ms)
				{
					if (string.IsNullOrEmpty(n))
					{
						if (m == cm && n == null)
							continue;
					}
					else
					{
						if (string.Compare(n, m.Name, StringComparison.OrdinalIgnoreCase) != 0)
							continue;
					}

					@as = m.GetCustomAttributes(typeof(SqlFunctionAttribute), true);//function
					if (@as != null && @as.Length > 0)
					{
						var sfa = @as[NAME] as SqlFunctionAttribute;
						cmd.Parameters[NAME].Value = sfa.Name;
						if (string.IsNullOrEmpty(cmd.Parameters[NAME].Value as string))
							cmd.Parameters[NAME].Value = m.Name;
						cmd.Parameters[DROP].Value = string.Format("IF EXISTS (SELECT * FROM [sys].[objects] WHERE [name] = N'{0}')", cmd.Parameters[NAME].Value) +
							Environment.NewLine + string.Format("\tDROP FUNCTION [{0}]", cmd.Parameters[NAME].Value);
						if (typeof(IEnumerable) == m.ReturnType)
							cmd.Parameters[GRANT].Value = string.Format("GRANT SELECT ON [dbo].[{0}] TO [public]", cmd.Parameters[NAME].Value);
						else
							cmd.Parameters[GRANT].Value = string.Format("GRANT EXECUTE ON [dbo].[{0}] TO [public]", cmd.Parameters[NAME].Value);
						cmd.Parameters[ALTER].Value = string.Format("ALTER FUNCTION [dbo].[{0}]", cmd.Parameters[NAME].Value);
						cmd.Parameters[BACKUP].Value = string.Format("ALTER FUNCTION [dbo].[{0}]", cmd.Parameters[NAME].Value);
						cmd.Parameters[CREATE].Value = string.Format("CREATE FUNCTION [dbo].[{0}]", cmd.Parameters[NAME].Value);
						var ps = m.GetParameters();
						var pp = string.Empty;
						var dd = string.Empty;
						@as = m.GetCustomAttributes(typeof(DescriptionAttribute), true);
						if (@as != null && @as.Length > 0)
							dd += string.Format(SQL_PROPERTY, "FUNCTION", cmd.Parameters[NAME].Value, string.Empty, (@as[0] as DescriptionAttribute).Description);
						foreach (var p in ps)
						{
							if (!string.IsNullOrEmpty(pp))
								pp += ", ";
							pp = pp + string.Format("@{0} ", p.Name) + GetSqlTypeDeclare(p.ParameterType, null, string.Empty);// +" = NULL";
							@as = p.GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[];
							if (@as != null && @as.Length > 0)
								dd += string.Format(SQL_PROPERTY, "FUNCTION", cmd.Parameters[NAME].Value, "-" + p.Name, (@as[0] as DescriptionAttribute).Description);
						}
						@as = m.ReturnParameter.GetCustomAttributes(typeof(DescriptionAttribute), true);
						if (@as != null && @as.Length > 0)
							dd += string.Format(SQL_PROPERTY, "FUNCTION", cmd.Parameters[NAME].Value, "-" + cmd.Parameters[NAME].Value, (@as[0] as DescriptionAttribute).Description);
						if (dd == string.Empty)
							dd = null;
						pp = string.Format("({0})", pp) +
							Environment.NewLine + string.Format("RETURNS {0} WITH EXECUTE AS CALLER", GetSqlTypeDeclare(m.ReturnType, sfa.TableDefinition, null)) +
							Environment.NewLine + "AS" +
							Environment.NewLine + string.Format("EXTERNAL NAME [{0}].[{1}].[{2}]", an, t.FullName, m.Name);
						cmd.Parameters[ALTER].Value = cmd.Parameters[ALTER].Value + pp;
						cmd.Parameters[BACKUP].Value = cmd.Parameters[BACKUP].Value + pp.Replace("RETURNS TABLE", "RETURNS @TABLE TABLE").Replace("WITH EXECUTE", "--WITH EXECUTE").Replace("EXTERNAL NAME", "BEGIN" + Environment.NewLine + "RETURN" + (string.IsNullOrEmpty(sfa.TableDefinition) ? " NULL" : string.Empty) + "--EXTERNAL NAME") + Environment.NewLine + "END";
						cmd.Parameters[CREATE].Value = cmd.Parameters[CREATE].Value + pp;
						cmd.Parameters[PROPERTY].Value = dd;
						cmd.ExecuteNonQuery();
						continue;
					}

					@as = m.GetCustomAttributes(typeof(SqlProcedureAttribute), true);//procedure
					if (@as != null && @as.Length > 0)
					{
						var sfa = @as[0] as SqlProcedureAttribute;
						cmd.Parameters[NAME].Value = sfa.Name;
						if (string.IsNullOrEmpty(cmd.Parameters[NAME].Value as string))
							cmd.Parameters[NAME].Value = m.Name;
						cmd.Parameters[DROP].Value = string.Format("IF EXISTS (SELECT * FROM [sys].[objects] WHERE [name] = N'{0}')", cmd.Parameters[NAME].Value) +
							Environment.NewLine + string.Format("\tDROP PROCEDURE [{0}]", cmd.Parameters[NAME].Value);
						cmd.Parameters[GRANT].Value = string.Format("GRANT EXECUTE ON [dbo].[{0}] TO [public]", cmd.Parameters[NAME].Value);
						cmd.Parameters[ALTER].Value = string.Format("ALTER PROCEDURE [dbo].[{0}]", cmd.Parameters[NAME].Value);
						cmd.Parameters[BACKUP].Value = string.Format("ALTER PROCEDURE [dbo].[{0}]", cmd.Parameters[NAME].Value);
						cmd.Parameters[CREATE].Value = string.Format("CREATE PROCEDURE [dbo].[{0}]", cmd.Parameters[NAME].Value);
						var ps = m.GetParameters();
						var pp = string.Empty;
						var dd = string.Empty;
						@as = m.GetCustomAttributes(typeof(DescriptionAttribute), true);
						if (@as != null && @as.Length > 0)
							dd += string.Format(SQL_PROPERTY, "PROCEDURE", cmd.Parameters[NAME].Value, string.Empty, (@as[0] as DescriptionAttribute).Description);
						foreach (var p in ps)
						{
							if (!string.IsNullOrEmpty(pp))
								pp += ", ";
							pp = pp + string.Format("@{0} ", p.Name) + GetSqlTypeDeclare(p.ParameterType, null, string.Empty);// +" = NULL";
							@as = p.GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[];
							if (@as != null && @as.Length > 0)
								dd += string.Format(SQL_PROPERTY, "PROCEDURE", cmd.Parameters[NAME].Value, "-" + p.Name, (@as[0] as DescriptionAttribute).Description);
						}
						@as = m.ReturnParameter.GetCustomAttributes(typeof(DescriptionAttribute), true);
						if (@as != null && @as.Length > 0)
							dd += string.Format(SQL_PROPERTY, "PROCEDURE", cmd.Parameters[NAME].Value, "-" + cmd.Parameters[NAME].Value, (@as[0] as DescriptionAttribute).Description);
						if (dd == string.Empty)
							dd = null;
						if (!string.IsNullOrEmpty(pp))
							pp = string.Format("({0})", pp);
						pp = pp +
							Environment.NewLine + "AS" +
							Environment.NewLine + string.Format("EXTERNAL NAME [{0}].[{1}].[{2}]", an, t.FullName, m.Name);
						cmd.Parameters[ALTER].Value = cmd.Parameters[ALTER].Value + pp;
						cmd.Parameters[BACKUP].Value = cmd.Parameters[BACKUP].Value + pp.Replace("WITH EXECUTE", "--WITH EXECUTE").Replace("EXTERNAL NAME", "PRINT 'EXTERNAL NAME") + "'";
						cmd.Parameters[CREATE].Value = cmd.Parameters[CREATE].Value + pp;
						cmd.Parameters[PROPERTY].Value = dd;
						cmd.ExecuteNonQuery();
						continue;
					}

					if (SqlContext.IsAvailable && SqlContext.Pipe != null)
						SqlContext.Pipe.Send(t.AssemblyQualifiedName + "::" + m + string.Empty);
				}

				if (SqlContext.IsAvailable && SqlContext.Pipe != null)
					SqlContext.Pipe.Send(t.AssemblyQualifiedName);
			}
			cmd.Dispose();
			Common.CloseConnection(con, null);
			name = an;// a.FullName;
			return 0;
		}

		private static string GetSqlTypeDeclare(Type type, string table, string @default)
		{
			var @ref = string.Empty;
			if (type.IsByRef)
			{
				type = type.GetElementType();
				@ref = " OUTPUT";
			}
			if (@default == string.Empty)
				@default = " = NULL";
			if (typeof(SqlBinary) == type || typeof(byte[]) == type)
				return "[varbinary](MAX)" + @ref;

			if (typeof(SqlBoolean) == type || typeof(bool) == type)
				return "[bit]" + @default + @ref;

			if (typeof(SqlByte) == type || typeof(byte) == type)
				return "[tinyint]" + @default + @ref;

			if (typeof(SqlBytes) == type || typeof(byte[]) == type)
				return "[varbinary](MAX)" + @ref;

			if (typeof(SqlChars) == type || typeof(char[]) == type)
				return "[char](MAX)" + @ref;

			if (typeof(SqlDateTime) == type || typeof(DateTime) == type)
				return "[datetime]" + @default + @ref;

			if (typeof(DateTimeOffset) == type || typeof(Nullable<DateTimeOffset>) == type)
				return "[datetimeoffset]" + @default + @ref;

			if (typeof(SqlDecimal) == type || typeof(decimal) == type)
				return "[decimal](24, 4)" + @default + @ref;

			if (typeof(SqlDouble) == type || typeof(double) == type)
				return "[float]" + @default + @ref;

			if (typeof(SqlGuid) == type || typeof(Guid) == type)
				return "[uniqueidentifier]" + @default + @ref;

			if (typeof(SqlInt16) == type || typeof(short) == type)
				return "[smallint]" + @default + @ref;

			if (typeof(SqlInt32) == type || typeof(int) == type)
				return "[int]" + @default + @ref;

			if (typeof(SqlInt64) == type || typeof(long) == type)
				return "[bigint]" + @default + @ref;

			if (typeof(SqlMoney) == type)// || typeof(money) == type)
				return "[money]" + @default + @ref;

			if (typeof(SqlSingle) == type || typeof(float) == type)
				return "[real]" + @default + @ref;

			if (typeof(SqlString) == type || typeof(string) == type)
				return "[nvarchar](MAX)" + @ref;

			if (typeof(SqlXml) == type)// || typeof(XmlDocument) == type)
				return "[xml]" + @ref;

			if (typeof(IEnumerable) == type)
			{
				if (string.IsNullOrEmpty(table))
					return "TABLE";

				return string.Format("TABLE ({0})", table);
			}

			return "[sql_variant]" + @default + @ref;
		}

		/// <summary/>
		[SqlFunction(DataAccess = DataAccessKind.Read)]
		[Description("获取脚本值")]
		public static SqlBinary GetSqlValue([Description("要执行脚本命令行")]SqlString sql, [Description("要执行脚本参数，可指定大小；如：@p0@p1@id@name@value*32@data(128)")]SqlString parameters, [Description("参数一")]SqlBinary p0, [Description("参数二")]SqlBinary p1, [Description("参数三")]SqlBinary p2, [Description("参数四")]SqlBinary p3, [Description("参数五")]SqlBinary p4, [Description("参数六")]SqlBinary p5, [Description("参数七")]SqlBinary p6, [Description("参数八")]SqlBinary p7, [Description("参数九")]SqlBinary p8, [Description("参数十")]SqlBinary p9)
		{
			var v = Common.Inner_ExecuteSql(sql, parameters, new SqlBinary[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9 }, context: SqlString.Null, isTvf1OrProcedure2: 0);
			return Common.ToBinary(v);
		}

		/// <summary/>
		[SqlFunction(DataAccess = DataAccessKind.Read, IsDeterministic = true)]
		[Description("确定性的获取脚本值")]
		public static SqlBinary GetSqlValueDeterministic([Description("要执行脚本命令行")]SqlString sql, [Description("要执行脚本参数，可指定大小；如：@p0@p1@id@name@value*32@data(128)")]SqlString parameters, [Description("参数一")]SqlBinary p0, [Description("参数二")]SqlBinary p1, [Description("参数三")]SqlBinary p2, [Description("参数四")]SqlBinary p3, [Description("参数五")]SqlBinary p4, [Description("参数六")]SqlBinary p5, [Description("参数七")]SqlBinary p6, [Description("参数八")]SqlBinary p7, [Description("参数九")]SqlBinary p8, [Description("参数十")]SqlBinary p9, [Description("连接字符串或确定识别（任意数字或字母）符，空表示当前连接")]SqlString context)
		{
			var v = Common.Inner_ExecuteSql(sql, parameters, new SqlBinary[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9 }, context, isTvf1OrProcedure2: 0);
			return Common.ToBinary(v);
		}

		/// <summary/>
		[SqlFunction(DataAccess = DataAccessKind.Read, FillRowMethodName = "FillSqlEnumerable", TableDefinition = "[id] [bigint]/* NOT NULL*/, [name] [nvarchar](max), [data] [varbinary](max), [value] [decimal](24, 4)/* NOT NULL*/, [time] [datetime]/* NOT NULL*/")]
		[Description("获取脚本值")]
		public static IEnumerable GetSqlValues([Description("要执行脚本命令行")]SqlString sql, [Description("要执行脚本参数，可指定大小；如：@p0@p1@id@name@value*32@data(128)")]SqlString parameters, [Description("参数一")]SqlBinary p0, [Description("参数二")]SqlBinary p1, [Description("参数三")]SqlBinary p2, [Description("参数四")]SqlBinary p3, [Description("参数五")]SqlBinary p4, [Description("参数六")]SqlBinary p5, [Description("参数七")]SqlBinary p6, [Description("参数八")]SqlBinary p7, [Description("参数九")]SqlBinary p8, [Description("参数十")]SqlBinary p9)
		{
			var v = Common.Inner_ExecuteSql(sql, parameters, new SqlBinary[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9 }, context: SqlString.Null, isTvf1OrProcedure2: 1);
			if (v is IEnumerable)
				return (IEnumerable)v;

			return new object[] { v };
		}

		/// <summary/>
		[SqlFunction(DataAccess = DataAccessKind.Read, FillRowMethodName = "FillSqlEnumerable", TableDefinition = "[id] [bigint]/* NOT NULL*/, [name] [nvarchar](max), [data] [varbinary](max), [value] [decimal](24, 4)/* NOT NULL*/, [time] [datetime]/* NOT NULL*/", IsDeterministic = true)]
		[Description("确定性的获取脚本值")]
		public static IEnumerable GetSqlValuesDeterministic([Description("要执行脚本命令行")]SqlString sql, [Description("要执行脚本参数，可指定大小；如：@p0@p1@id@name@value*32@data(128)")]SqlString parameters, [Description("参数一")]SqlBinary p0, [Description("参数二")]SqlBinary p1, [Description("参数三")]SqlBinary p2, [Description("参数四")]SqlBinary p3, [Description("参数五")]SqlBinary p4, [Description("参数六")]SqlBinary p5, [Description("参数七")]SqlBinary p6, [Description("参数八")]SqlBinary p7, [Description("参数九")]SqlBinary p8, [Description("参数十")]SqlBinary p9, [Description("连接字符串或确定识别（任意数字或字母）符，空表示当前连接")]SqlString context)
		{
			var v = Common.Inner_ExecuteSql(sql, parameters, new SqlBinary[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9 }, context, isTvf1OrProcedure2: 1);
			if (v is IEnumerable)
				return (IEnumerable)v;

			return new object[] { v };
		}

		private static void FillSqlEnumerable(object item, out SqlInt64 id, out SqlString name, out SqlBinary data, out SqlDecimal value, out SqlDateTime time)
		{
			var os = item as object[];
			if (os == null)
				os = new object[] { item };
			id = SqlInt64.MinValue;
			name = SqlString.Null;
			data = SqlBinary.Null;
			value = decimal.Zero;
			time = SqlDateTime.MinValue;
			for (var i = 0; i < os.Length; i++)
			{
				item = os[i];
				if (item is INullable && ((INullable)item).IsNull)
					continue;

				if (item is SqlInt64)
				{
					id = (SqlInt64)item;
				}
				else if (item is Int64)
				{
					id = (Int64)item;
				}
				else if (item is SqlString)
				{
					name = (SqlString)item;
				}
				else if (item is String)
				{
					name = item as String;
				}
				else if (item is SqlBinary)
				{
					data = (SqlBinary)item;
				}
				else if (item is SqlBytes)
				{
					data = ((SqlBytes)item).Value;
				}
				else if (item is Byte[])
				{
					data = item as Byte[];
				}
				else if (item is SqlDecimal)
				{
					value = (SqlDecimal)item;
				}
				else if (item is Decimal)
				{
					value = (Decimal)item;
				}
				else if (item is SqlDouble)
				{
					value = new SqlDecimal(((SqlDouble)item).Value);
				}
				else if (item is Double)
				{
					value = new SqlDecimal(((Double)item));
				}
				else if (item is SqlSingle)
				{
					value = new SqlDecimal(((SqlSingle)item).Value);
				}
				else if (item is Single)
				{
					value = new SqlDecimal((Single)item);
				}
				else if (item is SqlInt32)
				{
					value = (SqlInt32)item;
				}
				else if (item is Int32)
				{
					value = (Int32)item;
				}
				else if (item is SqlInt16)
				{
					value = (SqlInt16)item;
				}
				else if (item is Int16)
				{
					value = (Int16)item;
				}
				else if (item is SqlByte)
				{
					value = (SqlByte)item;
				}
				else if (item is Byte)
				{
					value = (Byte)item;
				}
				else if (item is SqlDateTime)
				{
					time = (SqlDateTime)item;
				}
				else if (item is DateTime)
				{
					time = (DateTime)item;
				}
			}
		}

		/// <summary/>
		[SqlProcedure]
		[Description("执行脚本")]
		public static int ExecuteSql([Description("要执行脚本命令行")]SqlString sql, [Description("要执行脚本参数，可指定大小；如：@p0@p1@id@name@value*32@data(128)")]SqlString parameters, [Description("参数一")]ref SqlBinary p0, [Description("参数二")]ref SqlBinary p1, [Description("参数三")]ref SqlBinary p2, [Description("参数四")]ref SqlBinary p3, [Description("参数五")]ref SqlBinary p4, [Description("参数六")]ref SqlBinary p5, [Description("参数七")]ref SqlBinary p6, [Description("参数八")]ref SqlBinary p7, [Description("参数九")]ref SqlBinary p8, [Description("参数十")]ref SqlBinary p9, [Description("连接字符串或确定识别（任意数字或字母）符，空表示当前连接")]SqlString context)
		{
			var p = new SqlBinary[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9 };
			var v = Common.Inner_ExecuteSql(sql, parameters, p, context, isTvf1OrProcedure2: 2);
			p0 = p[0];
			p1 = p[1];
			p2 = p[2];
			p3 = p[3];
			p4 = p[4];
			p5 = p[5];
			p6 = p[6];
			p7 = p[7];
			p8 = p[8];
			p9 = p[9];
			if (v is int)
				return (int)v;

			if (SqlContext.IsAvailable && SqlContext.Pipe != null)
				SqlContext.Pipe.Send(v is byte[] ? Encoding.Default.GetString((byte[])v) : v + string.Empty);
			return -1;
		}

		internal static object Inner_ExecuteSql(SqlString sql, SqlString parameters, SqlBinary[] ps, SqlString context, int isTvf1OrProcedure2)
		{
			if (sql.IsNull)
				return "SELECT <column name:varbinary(max)> FROM <table name> WHERE <condition column 0> = @p0 AND (<condition column 1> = @p1 OR <condition column 2> <> @p2) AND ...\r\nparamters: @p0@p1*4000@p2(8000)@p3@p4*size@p5(size)@p6@p7@p8@p9";

			var cs = context.IsNull ? null : context.Value;
			var con = Common.OpenConnection(cs);
			try
			{
				using (var cmd = con.CreateCommand())
				{
					cmd.CommandText = sql.Value;
					if (isTvf1OrProcedure2 > 1)
						return Common.ExecuteProcedure(parameters, ps, cmd);

					if (isTvf1OrProcedure2 > 0)
						return Common.ExecuteFS(parameters, ps, cmd);

					return Common.ExecuteFT(parameters, ps, cmd);
				}
			}
			finally
			{
				Common.CloseConnection(con, cs);
			}
		}
		internal static int ExecuteProcedure(SqlString parameters, SqlBinary[] ps, SqlCommand cmd)
		{
			var v = 0;
			cmd = Common.FillExecuteCommand(parameters, ps, cmd, true);
			if (SqlContext.IsAvailable && SqlContext.Pipe != null)
				SqlContext.Pipe.ExecuteAndSend(cmd);
			else
				v = cmd.ExecuteNonQuery();
			for (var i = ((ps.Length > cmd.Parameters.Count) ? (cmd.Parameters.Count - 1) : (ps.Length - 1)); i >= 0; i--)
			{
				var p = cmd.Parameters[i].Value;
				if (p == null || p == DBNull.Value)
					ps[i] = SqlBinary.Null;
				else if (p is SqlBinary)
					ps[i] = (SqlBinary)p;
				else if (p is byte[])
					ps[i] = new SqlBinary(p as byte[]);
				else
					ps[i] = SqlBinary.Null;
			}
			return v;
		}
		internal static IEnumerable ExecuteFS(SqlString parameters, SqlBinary[] ps, SqlCommand cmd)
		{
			var a = new ArrayList();
			using (var dr = Common.FillExecuteCommand(parameters, ps, cmd, false).ExecuteReader(CommandBehavior.CloseConnection))
			{
				do
				{
					while (dr.Read())
					{
						var os = new object[dr.FieldCount];
						dr.GetValues(os);
						a.Add(os);
					}
				} while (dr.NextResult());
				dr.Close();
			}
			return a;
		}
		internal static object ExecuteFT(SqlString parameters, SqlBinary[] ps, SqlCommand cmd)
		{
			return Common.FillExecuteCommand(parameters, ps, cmd, false).ExecuteScalar();
		}
		internal static SqlCommand FillExecuteCommand(SqlString parameters, SqlBinary[] ps, SqlCommand cmd, bool isProcedure)
		{
			var ts = Common.EmptyStringArray;
			if (!parameters.IsNull && parameters.Value != string.Empty)
				ts = parameters.Value.Split(new char[] { '\r', '\n', '\t', '\0', '|', ',', ';', '/', '@', '#', '$', '%', '&', ' ' }, StringSplitOptions.RemoveEmptyEntries);
			for (var i = 0; i < ts.Length; i++)
			{
				var p = new SqlParameter();
				if (ts[i].IndexOf('*') > 0)
				{
					var ii = ts[i].IndexOf('*');
					var t = ts[i].Substring(ii + 1);
					ts[i] = ts[i].Remove(ii);
					if (int.TryParse(t, out ii))
						p.Size = ii;
				}
				else if (ts[i].IndexOf('(') > 0)
				{
					var ii = ts[i].IndexOf('(');
					var t = ts[i].Substring(ii + 1);
					ts[i] = ts[i].Remove(ii);
					ii = t.IndexOf(')');
					t = t.Remove(ii);
					if (int.TryParse(t, out ii))
						p.Size = ii;
				}
				if (ts[i][0] == '@')
					p.ParameterName = ts[i];
				else
					p.ParameterName = '@' + ts[i];
				p.SqlDbType = SqlDbType.VarBinary;
				if (isProcedure)
					p.Direction = ParameterDirection.InputOutput;
				p.Value = ps[i];
				cmd.Parameters.Add(p);
			}
			return cmd;
		}

		internal static SqlBinary ToBinary(object value)
		{
			if (value is SqlBinary)
				return (SqlBinary)value;

			if (value is Byte[])
				return value as Byte[];

			if (value is INullable && ((INullable)value).IsNull)
				return SqlBinary.Null;

			if (value is SqlString)
				return Encoding.Default.GetBytes(((SqlString)value).Value);

			if (value is String)
				return Encoding.Default.GetBytes(value as String);

			if (value is SqlInt64)
				return BitConverter.GetBytes(((SqlInt64)value).Value);

			if (value is Int64)
				return BitConverter.GetBytes((Int64)value);

			if (value is SqlInt32)
				return BitConverter.GetBytes(((SqlInt32)value).Value);

			if (value is Int32)
				return BitConverter.GetBytes((Int32)value);

			if (value is SqlInt16)
				return BitConverter.GetBytes(((SqlInt16)value).Value);

			if (value is Int16)
				return BitConverter.GetBytes((Int16)value);

			if (value is SqlSingle)
				return BitConverter.GetBytes(((SqlSingle)value).Value);

			if (value is Single)
				return BitConverter.GetBytes((Single)value);

			if (value is SqlDouble)
				return BitConverter.GetBytes(((SqlDouble)value).Value);

			if (value is Double)
				return BitConverter.GetBytes((Double)value);

			if (value is SqlDecimal)
				return ((SqlDecimal)value).BinData;

			if (value is Decimal)
				return new SqlDecimal(((Decimal)value)).BinData;

			if (value is SqlDateTime)
				return BitConverter.GetBytes(((SqlDateTime)value).Value.Ticks);

			if (value is DateTime)
				return BitConverter.GetBytes(((DateTime)value).Ticks);

			if (value is DateTimeOffset)
				return BitConverter.GetBytes(((DateTimeOffset)value).UtcTicks);

			if (value is SqlGuid)
				return ((SqlGuid)value).ToByteArray();

			if (value is Guid)
				return ((Guid)value).ToByteArray();

			return SqlBinary.Null;
		}

		#region items

		/// <summary/>
		private static SqlInt32 Inner_SetItem(SqlString key, ref SqlBinary value, SqlString table, SqlInt32 validity, SqlDateTime timeout, SqlString context)
		{
			if (key.IsNull)
			{
				value = BitConverter.GetBytes(Common.ItemData.Count);
				return SqlInt32.Null;
			}

			var t = table.IsNull || table.Value == null ? null : Common.GetTableName(table.Value, null, false);
			if (t == null)//静态变量存储
			{
				if (value.IsNull || value.Value == null)
					value = new SqlBinary(Common.ItemData.Get(key.Value));
				else
					Common.ItemData.Set(key.Value, value.Value, validity: validity.IsNull ? 0L : TimeSpan.FromMilliseconds(validity.Value).Ticks, timeout: timeout.IsNull ? 0L : timeout.Value.Ticks);
				return 0;
			}

			if (t.IndexOf(':') >= 0 || t.IndexOf('/') >= 0 || t.IndexOf('\\') >= 0)
			{
				#region 文件存储

				if (!timeout.IsNull)
				{
					if (!value.IsNull)
						throw new ArgumentOutOfRangeException("over", "the [over] must be null if table is file path.");

					if (File.Exists(t))
						value = new SqlBinary(File.ReadAllBytes(t));
					return 0;
				}

				if (value.IsNull)
				{
					if (File.Exists(t))
						File.Delete(t);
				}
				else
				{
					if (Directory.Exists(Path.GetDirectoryName(t)))
						Directory.CreateDirectory(Path.GetDirectoryName(t));
					File.WriteAllBytes(t, value.Value);
				}

				#endregion

				return 0;
			}

			#region database table

			var cs = context.IsNull ? null : context.Value;
			var con = Common.OpenConnection(cs);
			using (var cmd = con.CreateCommand())
			{
				cmd.CommandText = string.Format(@"
DECLARE @db INT;
DECLARE @add DATETIME;
IF @value IS NULL AND (@over IS NULL OR CONVERT(INT, @over) < 0) ---------------------------------------- 获取值 或函数调用
BEGIN
	SET @db = OBJECT_ID(N'{1}');
	IF @db IS NULL
	BEGIN
		SELECT NULL [value]; ---------------------------------------- 如果表对象不存在
	END
	ELSE IF Objectproperty(@db, 'IsProcedure') Is NULL OR Objectproperty(@db, 'IsProcedure') = 0
	BEGIN
		SELECT @db = db_id(), @add = getdate();
		SELECT [value] FROM {0} WITH (NOLOCK) WHERE ([over] IS NULL OR [over] >= @add) AND [key] = @key;-- AND [database] = @db;
	END;
	ELSE -- 是存储过程
	BEGIN
		EXECUTE {0} @key = @key, @value = @value, @over = @over;
	END;
END
ELSE ---------------------------------------- 设置值
BEGIN
	SET @db = OBJECT_ID(N'{1}');
	IF @db IS NULL OR Objectproperty(@db, 'IsProcedure') Is NULL OR Objectproperty(@db, 'IsProcedure') = 0
	BEGIN
		IF @db IS NULL ---------------------------------------- 创建表
		BEGIN
			CREATE TABLE {0}([id] BIGINT NOT NULL IDENTITY (0, 1), [session] INT NOT NULL, [database] INT NOT NULL, [key] VARCHAR(512) NOT NULL, [value] VARBINARY(MAX) NULL, [add] DATETIME NOT NULL, [over] DATETIME NULL, [version] TIMESTAMP NOT NULL, PRIMARY KEY([key])); --, PRIMARY KEY([database], [key])); --
			SELECT @db = db_id(), @add = getdate();
			INSERT INTO {0} WITH(UPDLOCK, NOWAIT)([add], [key], [value], [over], [session], [database])-- VALUES(@add, '', CONVERT(VARBINARY(MAX), @sql), NULL, @@spid, @db);
				SELECT @add, [key], CONVERT(VARBINARY(MAX), convert(NVARCHAR(MAX), [text])), NULL, [spid], [dbid]--@db--
				FROM (SELECT @@spid [sid], '' [key]) AS [*]
				LEFT JOIN (SELECT [spid], [sql_handle], [dbid] FROM [sys].[sysprocesses]) AS [-]
				ON [sid] = [spid]
				OUTER/*CROSS*/ APPLY (SELECT [text] FROM [sys].[fn_get_sql]([sql_handle]) WHERE NOT [text] IS NULL) AS [+]
		END;
		ELSE
		BEGIN
			SELECT @db = db_id(), @add = getdate();
		END;
		IF @value IS NULL AND NOT @over IS NULL
		BEGIN
			UPDATE {0} WITH(READPAST, UPDLOCK, NOWAIT) SET [over] = @over, [session] = @@spid WHERE [key] = @key;-- AND [database] = @db;
			SELECT @value = [value] FROM {0} WITH (NOLOCK) WHERE [key] = @key;-- AND [database] = @db;
		END
		ELSE IF @value IS NULL
		BEGIN
			SELECT @value = [value] FROM {0} WITH (NOLOCK) WHERE [key] = @key;-- AND [database] = @db;
			DELETE FROM {0} WITH(READPAST, UPDLOCK, NOWAIT) WHERE ([over] < @add AND NOT [over] IS NULL) OR [key] = @key;--([key] = @key AND [database] = @db);
		END
		ELSE
		BEGIN
			IF EXISTS (SELECT NULL FROM {0} WITH (NOLOCK) WHERE [key] = @key)-- AND [database] = @db)
				UPDATE {0} WITH(READPAST, UPDLOCK, NOWAIT) SET [value] = @value, [over] = @over, [session] = @@spid WHERE [key] = @key;-- AND [database] = @db;
			ELSE
				INSERT INTO {0} WITH(UPDLOCK, NOWAIT)([add], [key], [value], [over], [session], [database]) VALUES(@add, @key, @value, @over, @@spid, @db);
			DELETE FROM {0} WITH(READPAST, UPDLOCK, NOWAIT) WHERE [over] < @add AND NOT [over] IS NULL;
		END;
		SELECT @value AS [value];
	END;
	ELSE -- 是存储过程
	BEGIN
		EXECUTE {0} @key = @key, @value = @value, @over = @over;
	END;
END;
", t, t[0] == '#' ? (@"tempdb.." + t) : t);
				cmd.Parameters.Clear();
				cmd.Parameters.Add(new SqlParameter("@key", SqlDbType.NVarChar, 512)).Value = key;
				cmd.Parameters.Add(new SqlParameter("@value", SqlDbType.VarBinary, -1)).Value = value;
				cmd.Parameters.Add(new SqlParameter("@over", SqlDbType.DateTime)).Value = timeout;
				cmd.Parameters.Add(new SqlParameter("@sql", SqlDbType.NVarChar, -1)).Value = DBNull.Value;
				var o = cmd.ExecuteScalar();
				if (o != null && o != DBNull.Value)
				{
					if (o is SqlBinary)
						value = (SqlBinary)o;
					else
						value = new SqlBinary(o as byte[]);
				}
				//deterministic = cmd.ExecuteNonQuery();
			}
			Common.CloseConnection(con, cs);

			#endregion

			return 0;
		}

		/// <summary/>
		[SqlProcedure]
		public static SqlInt32 SetItemValue([Description("暂存数据键")]SqlString key,
										[Description("暂存数据值")]ref SqlBinary value,
										[Description("暂存数据相对过期毫秒")]SqlInt32 validity,
										[Description("暂存数据绝对过期时间")]SqlDateTime timeout,
										[Description("暂存数据表或文件名，空表示静态内容")]SqlString table,
										[Description("连接字符串或确定识别（任意数字或字母）符，空表示当前连接")]SqlString context)
		{
			return Common.Inner_SetItem(key, ref value, table, validity, timeout, context);
		}

		/// <summary/>
		[SqlProcedure]
		[Description("获取暂存数据")]
		public static SqlInt32 WaitItemValue([Description("暂存数据键")]SqlString key, [Description("等待毫秒数")]SqlInt32 wait, [Description("确定性的获取暂存数据")] out SqlBinary value)
		{
			byte[] data;
			if (ItemData.Wait(key.IsNull ? null : key.Value, wait.IsNull ? 0 : wait.Value, out data))
			{
				if (data != null)
				{
					value = new SqlBinary(data);
					return new SqlInt32(1);
				}

				value = SqlBinary.Null;
				return new SqlInt32(-1);
			}

			value = SqlBinary.Null;
			return new SqlInt32(0);
		}

		/// <summary/>
		[SqlFunction(IsDeterministic = true, IsPrecise = false, DataAccess = DataAccessKind.Read)]
		[Description("确定性的设置暂存数据")]
		public static SqlInt32 SetItemDeterministic([Description("暂存数据键")]SqlString key,
										[Description("暂存数据值")]SqlBinary value,
										[Description("暂存数据相对过期毫秒")]SqlInt32 validity,
										[Description("暂存数据绝对过期时间")]SqlDateTime timeout,
										[Description("暂存数据表或文件名，空表示静态内容")]SqlString table,
										[Description("连接字符串或确定识别（任意数字或字母）符，空表示当前连接")]SqlString context)
		{
			return Common.Inner_SetItem(key, ref value, table, validity, timeout, context.IsNull ? SqlString.Null : context);
		}

		/// <summary/>
		[SqlFunction(DataAccess = DataAccessKind.Read)]
		[Description("设置暂存数据")]
		public static SqlInt32 SetItem([Description("暂存数据键")]SqlString key,
								[Description("暂存数据值")]SqlBinary value,
								[Description("暂存数据相对过期毫秒")]SqlInt32 validity,
								[Description("暂存数据绝对过期时间")]SqlDateTime timeout,
								[Description("暂存数据表或文件名，空表示静态内容")]SqlString table)
		{
			return Common.Inner_SetItem(key, ref value, table, validity, timeout, SqlString.Null);
		}

		/// <summary/>
		[SqlFunction(IsDeterministic = true, IsPrecise = false, DataAccess = DataAccessKind.Read)]
		[Description("确定性的获取暂存数据")]
		public static SqlBinary GetItemDeterministic([Description("暂存数据键")]SqlString key,
								[Description("暂存数据表或文件名，空表示静态内容")]SqlString table,
								[Description("连接字符串或确定识别（任意数字或字母）符，空表示当前连接")]SqlString context)
		{
			var v = SqlBinary.Null;
			Inner_SetItem(key, ref v, table, SqlInt32.Null, SqlDateTime.Null, SqlString.Null);
			return v;
		}

		/// <summary/>
		[SqlFunction(DataAccess = DataAccessKind.Read)]
		[Description("获取暂存数据")]
		public static SqlBinary GetItem([Description("暂存数据键")]SqlString key, [Description("暂存数据表或文件名，空表示静态内容")]SqlString table)
		{
			var v = SqlBinary.Null;
			Inner_SetItem(key, ref v, table, SqlInt32.Null, SqlDateTime.Null, SqlString.Null);
			return v;
		}

		/// <summary/>
		[SqlFunction(IsDeterministic = true, IsPrecise = false, DataAccess = DataAccessKind.Read)]
		[Description("确定性的获取暂存数据")]
		public static SqlBinary WaitItemDeterministic([Description("暂存数据键")]SqlString key, [Description("等待毫秒数")]SqlInt32 wait)
		{
			byte[] data;
			if (ItemData.Wait(key.IsNull ? null : key.Value, wait.IsNull ? 0 : wait.Value, out data) && data != null)
				return new SqlBinary(data);

			return SqlBinary.Null;
		}

		/// <summary/>
		[SqlFunction(DataAccess = DataAccessKind.Read)]
		[Description("获取暂存数据")]
		public static SqlBinary WaitItem([Description("暂存数据键")]SqlString key, [Description("等待毫秒数")]SqlInt32 wait)
		{
			byte[] data;
			if (ItemData.Wait(key.IsNull ? null : key.Value, wait.IsNull ? 0 : wait.Value, out data) && data != null)
				return new SqlBinary(data);

			return SqlBinary.Null;
		}

		/// <summary/>
		[SqlProcedure]
		[Description("初始化暂存数据，应用SQL存储过程代替")]
		public static SqlInt32 ItemInitialize([Description("连接字符串，默认为空：当前连接")]SqlString context)
		{
#if DEBUG
			SqlContext.Pipe.Send("内部版本。");
#endif
			SqlContext.Pipe.Send("请不要直接在这里调用 Clr 存储过程，而是用 T-SQL 重写调用 【SetItem】 存储过程来初始化全局变量。");
			return -1;
		}

		#endregion

		/// <summary/>
		[SqlFunction(IsDeterministic = true, IsPrecise = false)]
		[Description("格式化数据")]
		public static SqlString GetFormat([Description("要格式化的数据")]object input, [Description("格式化样式")]SqlString format)
		{
			if (input == null)
			{
				if (format.IsNull || string.IsNullOrEmpty(format.Value))
					return null;

				return new SqlString(string.Format(format.Value, input));
			}

			if (format.IsNull || string.IsNullOrEmpty(format.Value))
				return new SqlString(input.ToString());

			if (input is INullable)
			{
				if (((INullable)input).IsNull)
					return new SqlString(string.Format(format.Value, string.Empty));

				var t = input.GetType();
				var p = t.GetProperty("Value");
				if (p != null)
					input = p.GetValue(input, null);
			}

			return new SqlString(string.Format(format.Value, input));
		}

		#region get-tree

		/// <summary/>
		[SqlFunction(FillRowMethodName = "FillRowEnumerable", TableDefinition = "[result] [bigint]/* NOT NULL*/", DataAccess = DataAccessKind.Read)]
		[Description("获取树型结果表的所有子级记录，此成员会将所有记录放入内存，谨慎使用")]
		public static IEnumerable GetChildren([Description("要获取所有子级记录的树型结果表名")]SqlString table, [Description("主键字段名")]SqlString key, [Description("上级关联外键字段名")]SqlString parent, [Description("要获取的节点主键值")]SqlInt64 root, [Description("附加条件，默认为空")]SqlString where)
		{
			return GetTree(table.Value, key.Value, parent.Value, root.IsNull ? 0L : Math.Abs(root.Value), where.IsNull ? null : where.Value, true);
		}
		/// <summary/>
		[SqlFunction(FillRowMethodName = "FillRowEnumerable", TableDefinition = "[result] [bigint]/* NOT NULL*/", DataAccess = DataAccessKind.Read)]
		[Description("获取树型结果表的所有父级记录，此成员会将所有记录放入内存，谨慎使用")]
		public static IEnumerable GetAncestors([Description("要获取所有父级记录的树型结果表名")]SqlString table, [Description("主键字段名")]SqlString key, [Description("上级关联外键字段名")]SqlString parent, [Description("要获取的节点主键值")]SqlInt64 root, [Description("附加条件，默认为空")]SqlString where)
		{
			return GetTree(table.Value, key.Value, parent.Value, root.IsNull ? 0L : Math.Abs(root.Value), where.IsNull ? null : where.Value, false);
		}
		
		private static IEnumerable GetTree(string t, string k, string p, long v, string w, bool c)
		{
			var a = new ArrayList();
			//var con = Common.OpenConnection(null);
			using (var con = Common.OpenConnection(null))
			{
				using (var cmd = con.CreateCommand())
				//using (var cmd = new SqlCommand())
				//var cmd = new SqlCommand();
				{
					if (cmd.Connection == null)
						cmd.Connection = Common.OpenConnection(null);
					//cmd.CommandText = GetCommandText(t, k, p, r, w, true);
					//cmd.Parameters.Add(new SqlParameter("@root", SqlDbType.BigInt)).Value = root;
					FillCommandText(cmd, t[0] == '.' ? t.Substring(1) : t, k, p, v, w, c);
					if (SqlContext.IsAvailable && SqlContext.Pipe != null)
					{
						SqlContext.Pipe.ExecuteAndSend(cmd);
						return null;
					}

					if (t[0] == '.')
						return ExecuteReader(cmd);

					using (var dr = cmd.ExecuteReader())
					{
						do
						{
							while (dr.Read())
								a.Add(dr[0]);
						} while (dr.NextResult());
					}
				}
			}
			return a;
		}

		private static void FillCommandText(IDbCommand cmd, string t, string k, string p, long v, string w, bool c)
		{
			if (c)//children
				cmd.CommandText = @"
WITH t" + v + @"
(" + k + @"
--," + p + @"
)
AS
(
	SELECT " + k + @"--, " + p + @"
	FROM " + t + @"-- Anchor member definition
	WHERE (" + k + @" = @value OR " + p + @" = @value)" + (string.IsNullOrEmpty(w) ? string.Empty : (@" AND (" + w + @")")) + @"
	UNION ALL-- Recursive member definition
	SELECT c." + k + @"--, c." + p + @"
	FROM " + (string.IsNullOrEmpty(w) ? t : (@"(SELECT " + k + @", " + p + @" FROM " + t + @" WHERE " + w + @")")) + @" AS c
	INNER JOIN t" + v + @" AS p
	ON c." + p + @" = p." + k + @"
	WHERE c." + k + @" <> c." + p + @"
)
SELECT DISTINCT " + k + @" FROM t" + v + @";
";
			else//ancestors
				cmd.CommandText = @"
WITH t" + v + @"
(" + k + @"
," + p + @"
)
AS
(
	SELECT " + k + @", " + p + @"
	FROM " + t + @"-- Anchor member definition
	WHERE " + k + @" = @value" + (string.IsNullOrEmpty(w) ? string.Empty : (@" AND (" + w + @")")) + @"
	UNION ALL-- Recursive member definition
	SELECT c." + k + @", c." + p + @"
	FROM " + (string.IsNullOrEmpty(w) ? t : (@"(SELECT " + k + @", " + p + @" FROM " + t + @" WHERE " + w + @")")) + @" AS c
	INNER JOIN t" + v + @" AS p
	ON c." + k + @" = p." + p + @"
	WHERE c." + k + @" <> c." + p + @"
)
SELECT DISTINCT " + k + @" FROM t" + v + @";
";
			//cmd.Parameters.Add(new SqlParameter("@value", SqlDbType.BigInt)).Value = v;
			var cp = cmd.CreateParameter();
			cp.ParameterName = "@value";
			cp.DbType = DbType.Int64;
			cp.Value = v;
			cmd.Parameters.Add(cp);
		}

		private static IEnumerable ExecuteReader(IDbCommand command)
		{
			try
			{
				if (command.Connection == null)
					command.Connection = OpenConnection(null);
				if (command.Connection.State == ConnectionState.Closed)//这里肯定为关闭，如果不执行此语句，定发生数据连接已关闭错误。
					command.Connection.Open();
			}
			catch (Exception x)
			{
				/*
消息 6260，级别 16，状态 1，第 1 行
从用户定义的表值函数获取新行时出错: 
System.InvalidOperationException: 在此上下文中不允许访问数据。此上下文可能是不带 DataAccessKind.Read 或 SystemDataAccessKind.Read 标记的函数或方法，也可能是从表值函数的 FillRow 方法为获取数据而进行的回调，还可能是 UDT 验证方法。
System.InvalidOperationException: 
   在 System.Data.SqlServer.Internal.ClrLevelContext.CheckSqlAccessReturnCode(SqlAccessApiReturnCode eRc)
   在 System.Data.SqlServer.Internal.ClrLevelContext.GetCurrentContext(SmiEventSink sink, Boolean throwIfNotASqlClrThread, Boolean fAllowImpersonation)
   在 Microsoft.SqlServer.Server.InProcLink.GetCurrentContext(SmiEventSink eventSink)
   在 Microsoft.SqlServer.Server.SmiContextFactory.GetCurrentContext()
   在 Microsoft.SqlServer.Server.SqlContext.get_CurrentContext()
   在 Microsoft.SqlServer.Server.SqlContext.get_Pipe()
   在 PickGold.SqlServer.Common.<ExecuteReader>d__0.MoveNext()
。
				*/
				if (SqlContext.IsAvailable && SqlContext.Pipe != null)
					SqlContext.Pipe.Send(x + string.Empty);
				yield break;
			}

			using (var dr = command.ExecuteReader())
			{
				for (; ; )
				{
					for (; ; )
					{
						try
						{
							if (!dr.Read())
								break;
						}
						catch (Exception x)
						{
							if (SqlContext.IsAvailable && SqlContext.Pipe != null)
								SqlContext.Pipe.Send(x + string.Empty);
							break;
						}

						yield return dr[0];
					}

					try
					{
						if (!dr.NextResult())
							break;
					}
					catch (Exception x)
					{
						if (SqlContext.IsAvailable && SqlContext.Pipe != null)
							SqlContext.Pipe.Send(x + string.Empty);
						break;
					}
				}
			}
		}

		#endregion

		/// <summary/>
		[SqlFunction(FillRowMethodName = "FillRowEnumerable", TableDefinition = "[result] [bigint]/* NOT NULL*/")]
		[Description("获取虚拟表内容")]
		public static IEnumerable GetEnumerable([Description("起始值")]SqlInt64 begin, [Description("结束值")]SqlInt64 end, [Description("步长")]SqlInt64 step)
		{
			var b = begin.IsNull ? 0L : begin.Value;
			var e = end.IsNull ? 0L : end.Value;
			var s = step.IsNull ? 0L : step.Value;
			if (s == 0L)
			{
				if (b <= e)
					s = 1L;
				else
					s = -1L;
			}
			for (; b <= e; b += s)
				yield return b;
		}

		private static void FillRowEnumerable(object item, out SqlInt64 result)
		{
			if (item == null)
			{
				result = SqlInt64.Null;
				return;
			}

			var os = item as object[];
			if (os != null)
			{
				if (os.Length == 0)
				{
					result = SqlInt64.Null;
					return;
				}

				item = os[0];
			}
			var dr = item as IDataRecord;
			if (dr != null)
				item = dr[0];
			if (item is SqlInt64)
				result = (SqlInt64)item;
			else if (item is Int64)
				result = (Int64)item;
			else if (item is Int64)
				result = (Int64)item;
			else
				result = SqlInt64.Null;
		}

		/// <summary/>
		[SqlFunction]
		[Description("获取随机数或序列")]
		public static SqlInt64 GetRandom()
		{
			var bs = new byte[sizeof(long)];
			if (Common._Random == null)
				Common._Random = new Random();
			Common._Random.NextBytes(bs);
			return BitConverter.ToInt64(bs, 0);
		}
	}

	interface IAggregate<TYPE, CLASS>: INullable
	{
		//void Init();

		//void Accumulate(TYPE value);

		//void Merge(CLASS value);

		//TYPE Terminate();
	}
}
